using System.Collections.Generic;
using System.Linq;
using HqlIntellisense.ConfigurationAbstraction;

namespace HQLAddin.ConfigurationInspector
{
	public class DynamicMapper
	{
		public static IEnumerable<IPersistentClassInformation> GetClasses(dynamic configuration)
		{
			//dont try to convert this to a linq expression.
			var classes = new List<IPersistentClassInformation>();
			foreach (var classMapping in configuration.ClassMappings)
			{
				classes.Add(MapClass(classMapping));
			}
			return classes;
		}

		public static IPersistentClassInformation MapClass(dynamic cm)
		{
			var persistentIdentifierProperty = cm.IdentifierProperty == null ? 
												null : 
												new PersistentIdentifierProperty(cm.IdentifierProperty.Name, MapValue(cm.IdentifierProperty.Value));

			var persistentClassInformation = new PersistentClassInformation
			                                 	{
			                                 		EntityName = cm.EntityName,
			                                 		ClassName = cm.ClassName,
			                                 		IdentifierProperty = persistentIdentifierProperty,
			                                 		Properties = MapProperties(cm.PropertyIterator)
			                                 	};
			return persistentClassInformation;
		}

		public static IEnumerable<IPersistentProperty> MapProperties(IEnumerable<dynamic> propertyIterator)
		{
			return propertyIterator
				.Select(p => new PersistentProperty(p.Name, MapValue(p.Value)))
				.OfType<IPersistentProperty>()
				.ToArray();
		}

		public static IPersistentValue MapValue(dynamic value)
		{
			if(NhTypes.Component.IsAssignableFrom(value.GetType()))
			{
				return new PersistentComponent(MapProperties(value.PropertyIterator));
			}
			if(NhTypes.Collection.IsAssignableFrom(value.GetType()))
			{
				return value.Element == null ? 
					new PersistentCollection(null) : 
					new PersistentCollection(MapValue(value.Element));
			}

			if(NhTypes.ToOne.IsAssignableFrom(value.GetType()))
			{
				return new PersistentToOne(value.ReferencedEntityName);
			}

			if(NhTypes.OneToMany.IsAssignableFrom(value.GetType()))
			{
				return new PersistentOneToMany(value.ReferencedEntityName);
			}
			return null;
		}
	}
}